/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
 * This file is part of Suneido - The Integrated Application Platform
 * see: http://www.suneido.com for more information.
 * 
 * Copyright (c) 2003 Suneido Software Corp. 
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation - version 2. 
 *
 * This program is distributed in the hope that it will be
 * useful, but WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE.  See the GNU General Public License in the file COPYING
 * for more details. 
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the Free
 * Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include "checksum.h"

typedef unsigned char uchar;

// compute the Adler-32 checksum of a data stream

#define BASE 65521L /* largest prime smaller than 65536 */
#define NMAX 5552
/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */

#define DO1(buf,i)  {s1 += buf[i]; s2 += s1;}
#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1)
#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2)
#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4)
#define DO16(buf)   DO8(buf,0); DO8(buf,8)

ulong checksum(ulong adler, void* p, int len)
	{
    ulong s1 = adler & 0xffff;
    ulong s2 = (adler >> 16) & 0xffff;
    int k;

    if (p == 0) 
		return 1;
	uchar* buf = (uchar*) p;

    while (len > 0)
		{
        k = len < NMAX ? len : NMAX;
        len -= k;
        while (k >= 16) 
			{
            DO16(buf);
			buf += 16;
            k -= 16;
			}
        if (k != 0)
			do 
				{
				s1 += *buf++;
				s2 += s1;
				} while (--k);
        s1 %= BASE;
        s2 %= BASE;
		}
    return (s2 << 16) | s1;
	}
